import React, { useState, useEffect, useRef, useCallback } from 'react';
import axios from 'axios';
import { io, Socket } from 'socket.io-client';
import EmojiPicker from 'emoji-picker-react';
import { BsEmojiSmileFill } from 'react-icons/bs';
import { useNavigate } from 'react-router-dom';

import './Dhat.css';
import '../assets/icons/iconfont.css';
import VoiceCall from '../components/VoiceCall';
import VideoCall from '../components/VideoCall';
import AIModal from '../components/AIModal';

import Icon from './Icon';

interface UserData {
  username: string;
  image: string;
  isLoggedIn: boolean;
}

interface Message {
  _id: string;
  from: string;
  to: string;
  message: string;
  messageType: string;
  timestamp: Date;
  isRecalled?: boolean;
  recalledAt?: Date;
  originalContent?: string;
}

interface DhatProps {
  currentUser: UserData;
  selectedUser: {
    username: string;
    image: string;
  };
  onBack: () => void;
}

const Dhat: React.FC<DhatProps> = ({ currentUser, selectedUser, onBack }) => {
  const navigate = useNavigate();
  const [messages, setMessages] = useState<Message[]>([]);
  const [newMessage, setNewMessage] = useState('');
  const [loading, setLoading] = useState(true);
  const [socket, setSocket] = useState<Socket | null>(null);
  const [isTyping, setIsTyping] = useState(false);
  const [typingTimeout, setTypingTimeout] = useState<ReturnType<
    typeof setTimeout
  > | null>(null);
  const [showEmojiPicker, setShowEmojiPicker] = useState(false);
  const [showPlusMenu, setShowPlusMenu] = useState(false);
  const [showCamera, setShowCamera] = useState(false);
  const [cameraMode, setCameraMode] = useState<'photo' | 'video'>('photo');
  const [isRecording, setIsRecording] = useState(false);
  const [mediaRecorder, setMediaRecorder] = useState<MediaRecorder | null>(
    null
  );
  const [showLocationPicker, setShowLocationPicker] = useState(false);
  const [recordingTime, setRecordingTime] = useState(0);
  const [playingVoiceId, setPlayingVoiceId] = useState<string | null>(null);
  const [currentLocation, setCurrentLocation] = useState<{
    latitude: number;
    longitude: number;
    address: string;
  } | null>(null);
  const [locationLoading, setLocationLoading] = useState(false);
  const [selectedMapLocation, setSelectedMapLocation] = useState<{
    latitude: number;
    longitude: number;
    address: string;
  } | null>(null);
  const [mapLoading, setMapLoading] = useState(false);
  const [showExportMenu, setShowExportMenu] = useState(false);
  const [isVoiceInputting, setIsVoiceInputting] = useState(false);

  // 语音视频通话相关状态
  const [showVoiceCall, setShowVoiceCall] = useState(false);
  const [showVideoCall, setShowVideoCall] = useState(false);
  const [callState, setCallState] = useState<
    'idle' | 'calling' | 'connected' | 'ended'
  >('idle');
  const [incomingCallData, setIncomingCallData] = useState<{
    type: 'voice' | 'video';
    offer: RTCSessionDescriptionInit;
    fromUser: {
      username: string;
      image: string;
    };
  } | null>(null);

  // AI弹窗相关状态
  const [showAIModal, setShowAIModal] = useState(false);
  const [selectedMessage, setSelectedMessage] = useState<{
    message: string;
    messageType: string;
  } | null>(null);

  const messagesEndRef = useRef<HTMLDivElement>(null);
  const videoRef = useRef<HTMLVideoElement>(null);
  const canvasRef = useRef<HTMLCanvasElement>(null);
  const streamRef = useRef<MediaStream | null>(null);
  const currentRecorderRef = useRef<MediaRecorder | null>(null);

  // 获取聊天背景图
  const getChatBackground = () => {
    const backgroundKey = `chatBackground_${selectedUser.username}`;
    return localStorage.getItem(backgroundKey);
  };

  // 初始化Socket连接
  useEffect(() => {
    let newSocket: Socket;
    let reconnectTimer: ReturnType<typeof setTimeout>;

    const connectSocket = () => {
      try {
        newSocket = io('http://localhost:3001', {
          transports: ['websocket', 'polling'],
          timeout: 20000,
          reconnection: true,
          reconnectionAttempts: 5,
          reconnectionDelay: 1000,
          forceNew: true,
        });

        setSocket(newSocket);

        // 连接成功
        newSocket.on('connect', () => {
          console.warn('Socket连接成功');
          newSocket.emit('user_login', currentUser.username);
        });

        // 连接错误
        newSocket.on('connect_error', error => {
          console.error('Socket连接失败:', error);
          if (reconnectTimer) clearTimeout(reconnectTimer);
          reconnectTimer = setTimeout(() => {
            console.warn('尝试重新连接...');
            connectSocket();
          }, 3000);
        });

        // 断开连接
        newSocket.on('disconnect', reason => {
          console.warn('Socket断开连接:', reason);
          if (reason === 'io server disconnect') {
            if (reconnectTimer) clearTimeout(reconnectTimer);
            reconnectTimer = setTimeout(() => {
              console.warn('服务器断开，尝试重新连接...');
              connectSocket();
            }, 1000);
          }
        });

        // 监听接收消息
        newSocket.on('receive_message', (message: Message) => {
          if (message.from === selectedUser.username) {
            setMessages(prev => [...prev, message]);
          }
        });

        // 监听消息发送确认
        newSocket.on('message_sent', (message: Message) => {
          setMessages(prev => {
            const updatedMessages = prev.map(msg => {
              if (
                msg.from === message.from &&
                msg.to === message.to &&
                msg.message === message.message &&
                msg.messageType === message.messageType &&
                /^\d+$/.test(msg._id) &&
                Math.abs(
                  new Date(msg.timestamp).getTime() -
                    new Date(message.timestamp).getTime()
                ) < 5000
              ) {
                console.warn('更新临时消息为真实消息', {
                  tempId: msg._id,
                  realId: message._id,
                });
                return message;
              }
              return msg;
            });
            return updatedMessages;
          });
          console.warn('消息发送成功', message);
        });

        // 监听消息发送错误
        newSocket.on('message_error', (error: unknown) => {
          console.error('消息发送失败', error);
          alert('消息发送失败，请重试');
        });

        // 监听消息被撤回
        newSocket.on(
          'message_recalled',
          (data: {
            messageId: string;
            from: string;
            to: string;
            recalledAt: Date;
          }) => {
            console.warn('收到消息撤回通知:', data);
            setMessages(prev =>
              prev.map(msg =>
                msg._id === data.messageId
                  ? {
                      ...msg,
                      isRecalled: true,
                      recalledAt: data.recalledAt,
                      originalContent: msg.message,
                      message: '此消息已被撤回',
                    }
                  : msg
              )
            );
          }
        );

        // 监听撤回消息成功确认
        newSocket.on(
          'message_recall_success',
          (data: {
            messageId: string;
            from: string;
            to: string;
            recalledAt: Date;
          }) => {
            console.warn('消息撤回成功:', data);
          }
        );

        // 监听用户正在输入
        newSocket.on('user_typing', (data: unknown) => {
          if (
            typeof data === 'object' &&
            data !== null &&
            'from' in data &&
            (data as { from: string }).from === selectedUser.username
          ) {
            setIsTyping(true);
          }
        });

        // 监听用户停止输入
        newSocket.on('user_stop_typing', (data: unknown) => {
          if (
            typeof data === 'object' &&
            data !== null &&
            'from' in data &&
            (data as { from: string }).from === selectedUser.username
          ) {
            setIsTyping(false);
          }
        });

        // 监听语音消息
        newSocket.on('receive_voice', (message: Message) => {
          if (message.from === selectedUser.username) {
            setMessages(prev => [...prev, message]);
          }
        });

        // 监听语音通话请求
        newSocket.on('voice_call_request', (data: any) => {
          console.log('收到语音通话请求:', data);
          if (data.fromUserId === selectedUser.username) {
            setIncomingCallData({
              type: 'voice',
              offer: data.offer,
              fromUser: {
                username: data.fromUserName || data.fromUserId,
                image:
                  data.fromUserImage ||
                  `https://api.dicebear.com/7.x/avataaars/svg?seed=${data.fromUserId}`,
              },
            });
            setShowVoiceCall(true);
          }
        });

        // 监听视频通话请求
        newSocket.on('video_call_request', (data: any) => {
          console.log('收到视频通话请求:', data);
          if (data.fromUserId === selectedUser.username) {
            setIncomingCallData({
              type: 'video',
              offer: data.offer,
              fromUser: {
                username: data.fromUserName || data.fromUserId,
                image:
                  data.fromUserImage ||
                  `https://api.dicebear.com/7.x/avataaars/svg?seed=${data.fromUserId}`,
              },
            });
            setShowVideoCall(true);
          }
        });

        // 监听通话结束
        newSocket.on('voice_call_ended', (data: any) => {
          console.log('语音通话已结束');
          setShowVoiceCall(false);
          setCallState('ended');
        });

        newSocket.on('video_call_ended', (data: any) => {
          console.log('视频通话已结束');
          setShowVideoCall(false);
          setCallState('ended');
        });

        // 监听通话错误
        newSocket.on('call_error', (data: any) => {
          console.error('通话错误:', data.message);
          alert(data.message || '通话失败');
          setShowVoiceCall(false);
          setShowVideoCall(false);
        });
      } catch (error) {
        console.error('Socket连接初始化失败', error);
      }
    };

    connectSocket();

    return () => {
      if (reconnectTimer) clearTimeout(reconnectTimer);
      if (newSocket) {
        newSocket.close();
      }
    };
  }, [currentUser.username, selectedUser.username]);

  // 获取聊天记录
  useEffect(() => {
    const fetchMessages = async () => {
      try {
        setLoading(true);
        const response = await axios.get(
          `http://localhost:3001/ysx/chat?from=${currentUser.username}&to=${selectedUser.username}`
        );

        if (response.data.code === 200) {
          setMessages(response.data.data);
        }
      } catch (error) {
        console.error('获取聊天记录失败:', error);
      } finally {
        setLoading(false);
      }
    };

    if (currentUser.username && selectedUser.username) {
      fetchMessages();
    }
  }, [currentUser.username, selectedUser.username]);

  // 自动滚动到底部
  useEffect(() => {
    messagesEndRef.current?.scrollIntoView({ behavior: 'smooth' });
  }, [messages]);

  // 发送消息
  const handleSendMessage = async () => {
    if (!newMessage.trim() || !socket) return;

    try {
      const newMsg: Message = {
        _id: Date.now().toString(),
        from: currentUser.username,
        to: selectedUser.username,
        message: newMessage,
        messageType: 'text',
        timestamp: new Date(),
      };

      setMessages(prev => [...prev, newMsg]);

      socket.emit('send_message', {
        from: currentUser.username,
        to: selectedUser.username,
        message: newMessage,
        messageType: 'text',
      });

      setNewMessage('');

      if (typingTimeout) {
        clearTimeout(typingTimeout);
      }

      socket.emit('stop_typing', {
        from: currentUser.username,
        to: selectedUser.username,
      });
    } catch (error) {
      console.error('发送消息失败', error);
    }
  };

  // 撤回消息
  const recallMessage = async (messageId: string) => {
    try {
      console.log('开始撤回消息', { messageId, from: currentUser.username });
      const response = await axios.put(
        'http://localhost:3001/ysx/chat/recall',
        {
          messageId,
          from: currentUser.username,
        }
      );

      console.log('撤回消息响应:', response.data);

      if (response.data.code === 200) {
        setMessages(prev =>
          prev.map(msg =>
            msg._id === messageId
              ? {
                  ...msg,
                  isRecalled: true,
                  recalledAt: new Date(),
                  originalContent: msg.message,
                  message: '此消息已被撤回',
                }
              : msg
          )
        );

        if (socket) {
          socket.emit('recall_message', {
            messageId,
            from: currentUser.username,
            to: selectedUser.username,
          });
        }

        console.log('消息撤回成功');
      } else {
        console.error('撤回失败:', response.data);
        alert(response.data.msg || '撤回失败');
      }
    } catch (error: any) {
      console.error('撤回消息失败:', error);
      if (error.response) {
        console.error('响应错误:', error.response.data);
        console.error('状态码:', error.response.status);
      }
      alert('撤回消息失败，请重试');
    }
  };

  // 发起语音通话
  const startVoiceCall = () => {
    if (!socket) {
      alert('连接不可用，请稍后重试');
      return;
    }
    setShowVoiceCall(true);
    setCallState('calling');
  };

  // 发起视频通话
  const startVideoCall = () => {
    if (!socket) {
      alert('连接不可用，请稍后重试');
      return;
    }
    setShowVideoCall(true);
    setCallState('calling');
  };

  // 处理通话状态变化
  const handleCallStateChange = (state: 'connected' | 'ended' | 'rejected') => {
    setCallState(state === 'connected' ? 'connected' : 'ended');
  };

  // 处理通话结束
  const handleCallEnded = (duration: number) => {
    console.log('通话结束，时长:', duration);
    // 可以在这里添加通话记录保存逻辑
  };

  // 关闭语音通话
  const closeVoiceCall = () => {
    setShowVoiceCall(false);
    setCallState('idle');
    setIncomingCallData(null);
  };

  // 关闭视频通话
  const closeVideoCall = () => {
    setShowVideoCall(false);
    setCallState('idle');
    setIncomingCallData(null);
  };

  // 处理消息点击，显示AI弹窗
  const handleMessageClick = (message: Message) => {
    // 只对对方发送的消息启用AI功能
    if (message.from === selectedUser.username) {
      let messageContent = '';

      // 根据消息类型提取内容
      switch (message.messageType) {
        case 'text':
          messageContent = message.message;
          break;
        case 'image':
          messageContent = '这是一张图片，请帮我分析图片内容';
          break;
        case 'file':
          try {
            const fileData = JSON.parse(message.message);
            messageContent = `这是一个文件：${fileData.name || '未知文件'}`;
          } catch {
            messageContent = '这是一个文件';
          }
          break;
        case 'location':
          try {
            const locationData = JSON.parse(message.message);
            messageContent = `位置信息：${locationData.address || '未知位置'}`;
          } catch {
            messageContent = '这是一个位置信息';
          }
          break;
        case 'voice':
          messageContent = '这是一条语音消息，请帮我分析语音内容';
          break;
        case 'video':
          messageContent = '这是一个视频文件，请帮我分析视频内容';
          break;
        default:
          messageContent = message.message;
      }

      setSelectedMessage({
        message: messageContent,
        messageType: message.messageType,
      });
      setShowAIModal(true);
    }
  };

  // 关闭AI弹窗
  const closeAIModal = () => {
    setShowAIModal(false);
    setSelectedMessage(null);
  };

  // 重新编辑消息
  const reEditMessage = (originalContent: string) => {
    setNewMessage(originalContent);
    const inputElement = document.querySelector(
      '.input-field'
    ) as HTMLInputElement;
    if (inputElement) {
      inputElement.focus();
    }
  };

  // 处理输入变化，发送正在输入状态
  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setNewMessage(e.target.value);

    if (socket) {
      socket.emit('typing', {
        from: currentUser.username,
        to: selectedUser.username,
      });

      if (typingTimeout) {
        clearTimeout(typingTimeout);
      }

      const timeout = setTimeout(() => {
        socket.emit('stop_typing', {
          from: currentUser.username,
          to: selectedUser.username,
        });
      }, 1000);

      setTypingTimeout(timeout);
    }
  };

  // 按回车发送
  const handleKeyPress = (e: React.KeyboardEvent) => {
    if (e.key === 'Enter' && !e.shiftKey) {
      e.preventDefault();
      handleSendMessage();
    }
  };

  // 格式化时间显示
  const formatTime = (date: Date) => {
    return new Date(date).toLocaleTimeString('zh-CN', {
      hour: '2-digit',
      minute: '2-digit',
    });
  };

  // 格式化文件大小
  const formatFileSize = (bytes: number) => {
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  };

  // 切换表情包选择器
  const toggleEmojiPicker = () => {
    setShowEmojiPicker(!showEmojiPicker);
  };

  // 选择表情
  const handleEmojiClick = (emojiObject: { emoji: string }) => {
    setNewMessage(prev => prev + emojiObject.emoji);
    setShowEmojiPicker(false);
  };

  // 切换加号菜单
  const togglePlusMenu = () => {
    setShowPlusMenu(!showPlusMenu);
    if (showEmojiPicker) {
      setShowEmojiPicker(false);
    }
  };

  // 处理图片上传
  const handleImageUpload = async (
    event: React.ChangeEvent<HTMLInputElement>
  ) => {
    const file = event.target.files?.[0];
    if (file) {
      if (!file.type.startsWith('image/')) {
        alert('请选择图片文件');
        return;
      }

      if (file.size > 5 * 1024 * 1024) {
        alert('图片大小不能超过5MB');
        return;
      }

      try {
        const formData = new FormData();
        formData.append('image', file);

        const uploadResponse = await axios.post(
          'http://localhost:3001/ysx/chat/image/upload',
          formData,
          {
            headers: {
              'Content-Type': 'multipart/form-data',
            },
          }
        );

        if (uploadResponse.data.code === 0) {
          const imageUrl = `http://localhost:3001${uploadResponse.data.data.imageUrl}`;
          const newMsg: Message = {
            _id: Date.now().toString(),
            from: currentUser.username,
            to: selectedUser.username,
            message: imageUrl,
            messageType: 'image',
            timestamp: new Date(),
          };

          setMessages(prev => [...prev, newMsg]);

          if (socket) {
            socket.emit('send_image', {
              from: currentUser.username,
              to: selectedUser.username,
              imageUrl: imageUrl,
              messageType: 'image',
            });
          }

          setShowPlusMenu(false);
        } else if (uploadResponse.data.code === -2) {
          alert(`图片审核不通过: ${uploadResponse.data.msg}`);
        } else if (uploadResponse.data.code === -3) {
          alert(`图片需人工审核: ${uploadResponse.data.msg}`);
        } else {
          alert('图片上传失败: ' + uploadResponse.data.msg);
        }
      } catch (error) {
        console.error('图片上传失败:', error);
        alert('图片上传失败，请重试');
      }

      event.target.value = '';
    }
  };

  // 处理文件上传
  const handleFileUpload = async (
    event: React.ChangeEvent<HTMLInputElement>
  ) => {
    const file = event.target.files?.[0];
    if (file) {
      if (file.size > 10 * 1024 * 1024) {
        alert('文件大小不能超过10MB');
        return;
      }

      try {
        const formData = new FormData();
        formData.append('file', file);

        const uploadResponse = await axios.post(
          'http://localhost:3001/ysx/upload-file',
          formData,
          {
            headers: {
              'Content-Type': 'multipart/form-data',
            },
          }
        );

        if (uploadResponse.data.code === 200) {
          const fileUrl = `http://localhost:3001${uploadResponse.data.data.fileUrl}`;
          const fileName = uploadResponse.data.data.originalName;
          const fileSize = uploadResponse.data.data.fileSize;

          const newMsg: Message = {
            _id: Date.now().toString(),
            from: currentUser.username,
            to: selectedUser.username,
            message: JSON.stringify({
              url: fileUrl,
              name: fileName,
              size: fileSize,
              type: file.type,
            }),
            messageType: 'file',
            timestamp: new Date(),
          };

          setMessages(prev => [...prev, newMsg]);

          if (socket) {
            socket.emit('send_file', {
              from: currentUser.username,
              to: selectedUser.username,
              fileUrl: fileUrl,
              fileName: fileName,
              fileSize: fileSize,
              messageType: 'file',
            });
          }

          setShowPlusMenu(false);
        } else {
          alert('文件上传失败: ' + uploadResponse.data.msg);
        }
      } catch (error) {
        console.error('文件上传失败:', error);
        alert('文件上传失败，请重试');
      }

      event.target.value = '';
    }
  };

  // 启动相机
  const startCamera = useCallback(async () => {
    try {
      const stream = await navigator.mediaDevices.getUserMedia({
        video: true,
        audio: cameraMode === 'video',
      });

      streamRef.current = stream;

      if (videoRef.current) {
        videoRef.current.srcObject = stream;
        videoRef.current.play();
      }
    } catch (error) {
      console.error('无法访问相机:', error);
      alert('无法访问相机，请检查权限设置');
    }
  }, [cameraMode]);

  // 停止相机
  const stopCamera = useCallback(() => {
    if (streamRef.current) {
      streamRef.current.getTracks().forEach(track => track.stop());
      streamRef.current = null;
    }

    if (videoRef.current) {
      videoRef.current.srcObject = null;
    }
  }, []);

  // 拍照
  const takePhoto = () => {
    if (videoRef.current && canvasRef.current) {
      const canvas = canvasRef.current;
      const video = videoRef.current;
      const context = canvas.getContext('2d');

      if (context) {
        canvas.width = video.videoWidth;
        canvas.height = video.videoHeight;
        context.drawImage(video, 0, 0);

        canvas.toBlob(
          async blob => {
            if (blob) {
              const file = new File([blob], `photo_${Date.now()}.jpg`, {
                type: 'image/jpeg',
              });

              try {
                const formData = new FormData();
                formData.append('image', file);

                const uploadResponse = await axios.post(
                  'http://localhost:3001/ysx/chat/image/upload',
                  formData,
                  {
                    headers: {
                      'Content-Type': 'multipart/form-data',
                    },
                  }
                );

                if (uploadResponse.data.code === 0) {
                  const imageUrl = `http://localhost:3001${uploadResponse.data.data.imageUrl}`;
                  const newMsg: Message = {
                    _id: Date.now().toString(),
                    from: currentUser.username,
                    to: selectedUser.username,
                    message: imageUrl,
                    messageType: 'image',
                    timestamp: new Date(),
                  };

                  setMessages(prev => [...prev, newMsg]);

                  if (socket) {
                    socket.emit('send_image', {
                      from: currentUser.username,
                      to: selectedUser.username,
                      imageUrl: imageUrl,
                      messageType: 'image',
                    });
                  }

                  setShowCamera(false);
                  stopCamera();
                } else {
                  alert('图片上传失败: ' + uploadResponse.data.msg);
                }
              } catch (error) {
                console.error('图片上传失败:', error);
                alert('图片上传失败，请重试');
              }
            }
          },
          'image/jpeg',
          0.8
        );
      }
    }
  };

  // 开始录制视频
  const startRecording = () => {
    if (streamRef.current) {
      const chunks: Blob[] = [];
      let mimeType = 'video/webm;codecs=vp9';

      if (!MediaRecorder.isTypeSupported(mimeType)) {
        mimeType = 'video/webm;codecs=vp8';
      }

      if (!MediaRecorder.isTypeSupported(mimeType)) {
        mimeType = 'video/webm';
      }

      if (!MediaRecorder.isTypeSupported(mimeType)) {
        mimeType = 'video/mp4';
      }

      const recorder = new MediaRecorder(streamRef.current, {
        mimeType: mimeType,
      });

      recorder.ondataavailable = event => {
        if (event.data.size > 0) {
          chunks.push(event.data);
        }
      };

      recorder.onstop = async () => {
        const blob = new Blob(chunks, { type: mimeType });
        const file = new File(
          [blob],
          `video_${Date.now()}.${mimeType.includes('webm') ? 'webm' : 'mp4'}`,
          { type: mimeType }
        );

        try {
          const formData = new FormData();
          formData.append('file', file);

          const uploadResponse = await axios.post(
            'http://localhost:3001/ysx/upload-file',
            formData,
            {
              headers: {
                'Content-Type': 'multipart/form-data',
              },
            }
          );

          if (uploadResponse.data.code === 200) {
            const fileUrl = `http://localhost:3001${uploadResponse.data.data.fileUrl}`;
            const fileName = uploadResponse.data.data.originalName;
            const fileSize = uploadResponse.data.data.fileSize;

            const newMsg: Message = {
              _id: Date.now().toString(),
              from: currentUser.username,
              to: selectedUser.username,
              message: JSON.stringify({
                url: fileUrl,
                name: fileName,
                size: fileSize,
                type: uploadResponse.data.data.mimeType,
              }),
              messageType: 'video',
              timestamp: new Date(),
            };

            setMessages(prev => [...prev, newMsg]);

            if (socket) {
              socket.emit('send_video', {
                from: currentUser.username,
                to: selectedUser.username,
                fileUrl: fileUrl,
                fileName: fileName,
                fileSize: fileSize,
                messageType: 'video',
                mimeType: uploadResponse.data.data.mimeType,
              });
            }

            setShowCamera(false);
            stopCamera();
          } else {
            alert('视频上传失败: ' + uploadResponse.data.msg);
          }
        } catch (error) {
          console.error('视频上传失败:', error);
          alert('视频上传失败，请重试');
        }
      };

      setMediaRecorder(recorder);
      recorder.start();
      setIsRecording(true);
    }
  };

  // 停止录制视频
  const stopRecording = () => {
    if (mediaRecorder && isRecording) {
      mediaRecorder.stop();
      setIsRecording(false);
    }
  };

  // 切换相机模式
  const toggleCameraMode = () => {
    setCameraMode(prev => (prev === 'photo' ? 'video' : 'photo'));
  };

  // 语音录制功能
  const handleVoiceRecord = async () => {
    if (!isRecording) {
      try {
        const stream = await navigator.mediaDevices.getUserMedia({
          audio: true,
        });

        const recorder = new MediaRecorder(stream);
        const chunks: Blob[] = [];
        let currentDuration = 0;

        recorder.ondataavailable = event => {
          if (event.data.size > 0) {
            chunks.push(event.data);
          }
        };

        recorder.onstop = () => {
          const audioBlob = new Blob(chunks, { type: 'audio/webm' });
          const audioUrl = URL.createObjectURL(audioBlob);
          sendVoiceMessage(audioUrl, currentDuration);
          stream.getTracks().forEach(track => track.stop());
        };

        setMediaRecorder(recorder);
        recorder.start();
        setIsRecording(true);
        setRecordingTime(0);

        const timer = setInterval(() => {
          currentDuration += 1;
          setRecordingTime(currentDuration);

          if (currentDuration >= 60) {
            clearInterval(timer);
            recorder.stop();
            setIsRecording(false);
          }
        }, 1000);

        (
          recorder as MediaRecorder & { timer: ReturnType<typeof setInterval> }
        ).timer = timer;

        const dataTimer = setInterval(() => {
          if (recorder.state === 'recording') {
            recorder.requestData();
          } else {
            clearInterval(dataTimer);
          }
        }, 1000);
      } catch (error) {
        console.error('无法访问麦克风', error);
        alert('无法访问麦克风，请检查权限设置');
      }
    } else {
      if (mediaRecorder && mediaRecorder.state === 'recording') {
        mediaRecorder.stop();
        clearInterval(
          (
            mediaRecorder as MediaRecorder & {
              timer: ReturnType<typeof setInterval>;
            }
          ).timer
        );
        setIsRecording(false);
      }
    }
  };

  // 发送语音消息
  const sendVoiceMessage = async (audioUrl: string, duration: number) => {
    if (!socket) return;

    try {
      const response = await fetch(audioUrl);
      const audioBlob = await response.blob();

      const formData = new FormData();
      const fileName = `voice_${currentUser.username}_${Date.now()}.webm`;
      formData.append('file', audioBlob, fileName);

      const uploadResponse = await axios.post(
        'http://localhost:3001/ysx/upload-file',
        formData,
        {
          headers: {
            'Content-Type': 'multipart/form-data',
          },
        }
      );

      if (uploadResponse.data.code === 200) {
        const fileUrl = `http://localhost:3001${uploadResponse.data.data.fileUrl}`;
        const fileName = uploadResponse.data.data.originalName;
        const fileSize = uploadResponse.data.data.fileSize;

        const newMsg: Message = {
          _id: Date.now().toString(),
          from: currentUser.username,
          to: selectedUser.username,
          message: JSON.stringify({
            url: fileUrl,
            name: fileName,
            size: fileSize,
            type: 'audio/webm',
            duration: duration,
          }),
          messageType: 'voice',
          timestamp: new Date(),
        };

        setMessages(prev => [...prev, newMsg]);

        socket.emit('send_voice', {
          from: currentUser.username,
          to: selectedUser.username,
          fileUrl: fileUrl,
          fileName: fileName,
          fileSize: fileSize,
          messageType: 'voice',
          duration: duration,
        });

        URL.revokeObjectURL(audioUrl);
      } else {
        alert('语音上传失败: ' + uploadResponse.data.msg);
      }
    } catch (error) {
      console.error('语音上传失败:', error);
      alert('语音上传失败，请重试');
    }
  };

  // 播放语音消息
  const playVoiceMessage = (audioUrl: string, messageId: string) => {
    if (audioUrl) {
      const audio = new Audio(audioUrl);
      setPlayingVoiceId(messageId);

      audio.onplay = () => {
        setPlayingVoiceId(messageId);
      };

      audio.onended = () => {
        setPlayingVoiceId(null);
      };

      audio.onerror = () => {
        console.error('播放语音失败');
        setPlayingVoiceId(null);
        alert('播放语音失败');
      };

      audio.play().catch(error => {
        console.error('播放语音失败:', error);
        setPlayingVoiceId(null);
        alert('播放语音失败');
      });
    }
  };

  // 语音输入转文字功能
  const handleVoiceInput = async () => {
    if (isVoiceInputting) {
      stopVoiceInput();
      return;
    }

    try {
      const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
      const recorder = new MediaRecorder(stream);
      const audioChunks: Blob[] = [];

      setIsVoiceInputting(true);

      recorder.ondataavailable = event => {
        audioChunks.push(event.data);
      };

      recorder.onstop = async () => {
        try {
          const audioBlob = new Blob(audioChunks, { type: 'audio/webm' });
          const formData = new FormData();
          formData.append('audio', audioBlob, 'voice_input.webm');

          const response = await axios.post(
            'http://localhost:3001/ysx/voice-to-text',
            formData,
            {
              headers: {
                'Content-Type': 'multipart/form-data',
              },
            }
          );

          if (response.data && response.data.data && response.data.data.text) {
            setNewMessage(response.data.data.text);
          } else {
            alert('语音识别失败，请重试');
          }
        } catch (error) {
          console.error('语音转文字失败', error);
          alert('语音转文字失败，请重试');
        } finally {
          setIsVoiceInputting(false);
        }
      };

      recorder.start();
      currentRecorderRef.current = recorder;
    } catch (error) {
      console.error('启动语音输入失败:', error);
      alert('无法访问麦克风，请检查权限设置');
      setIsVoiceInputting(false);
    }
  };

  // 停止语音输入
  const stopVoiceInput = () => {
    setIsVoiceInputting(false);
    if (currentRecorderRef.current) {
      currentRecorderRef.current.stop();
      currentRecorderRef.current = null;
    }
  };

  // 获取当前位置
  const getCurrentLocation = () => {
    setLocationLoading(true);

    if (navigator.geolocation) {
      navigator.geolocation.getCurrentPosition(
        async position => {
          const { latitude, longitude } = position.coords;

          try {
            const response = await axios.get(
              `http://localhost:3001/ysx/geocode?location=${longitude},${latitude}`
            );

            if (response.data.status === '1') {
              const address = response.data.regeocode.formatted_address;
              setCurrentLocation({
                latitude,
                longitude,
                address,
              });
            } else {
              alert('获取地址信息失败');
            }
          } catch (error) {
            console.error('获取地址失败:', error);
            alert('获取地址信息失败');
          } finally {
            setLocationLoading(false);
          }
        },
        error => {
          console.error('获取位置失败:', error);
          alert('无法获取当前位置，请检查位置权限');
          setLocationLoading(false);
        },
        {
          enableHighAccuracy: true,
          timeout: 10000,
          maximumAge: 60000,
        }
      );
    } else {
      alert('您的浏览器不支持地理位置功能');
      setLocationLoading(false);
    }
  };

  // 地图点击选择位置
  const handleMapClick = async (event: React.MouseEvent<HTMLDivElement>) => {
    const rect = event.currentTarget.getBoundingClientRect();
    const x = event.clientX - rect.left;
    const y = event.clientY - rect.top;

    const mapWidth = rect.width;
    const mapHeight = rect.height;
    const minLat = 39.4;
    const maxLat = 40.4;
    const minLng = 115.7;
    const maxLng = 117.4;

    const latitude = maxLat - (y / mapHeight) * (maxLat - minLat);
    const longitude = minLng + (x / mapWidth) * (maxLng - minLng);

    setMapLoading(true);

    try {
      const response = await axios.get(
        `http://localhost:3001/ysx/geocode?location=${longitude},${latitude}`
      );

      if (response.data.status === '1') {
        const address = response.data.regeocode.formatted_address;
        setSelectedMapLocation({
          latitude,
          longitude,
          address,
        });
      } else {
        alert('获取地址信息失败');
      }
    } catch (error) {
      console.error('获取地址失败:', error);
      alert('获取地址信息失败');
    } finally {
      setMapLoading(false);
    }
  };

  // 发送位置消息
  const sendLocation = async () => {
    if (!currentLocation && !selectedMapLocation) return;
    const locationToSend = selectedMapLocation || currentLocation;

    if (!locationToSend) return;

    try {
      const newMsg: Message = {
        _id: Date.now().toString(),
        from: currentUser.username,
        to: selectedUser.username,
        message: JSON.stringify({
          latitude: locationToSend.latitude,
          longitude: locationToSend.longitude,
          address: locationToSend.address,
          type: 'location',
        }),
        messageType: 'location',
        timestamp: new Date(),
      };

      setMessages(prev => [...prev, newMsg]);

      if (socket) {
        socket.emit('send_location', {
          from: currentUser.username,
          to: selectedUser.username,
          latitude: locationToSend.latitude,
          longitude: locationToSend.longitude,
          address: locationToSend.address,
          messageType: 'location',
        });
      }

      setShowLocationPicker(false);
      setCurrentLocation(null);
      setSelectedMapLocation(null);
    } catch (error) {
      console.error('发送位置失败', error);
      alert('发送位置失败，请重试');
    }
  };

  // 重置地图选择
  const resetMapSelection = () => {
    setSelectedMapLocation(null);
    setCurrentLocation(null);
  };

  // 相机弹窗显示时自动启动相机
  useEffect(() => {
    if (showCamera) {
      startCamera();
    } else {
      stopCamera();
    }
  }, [showCamera, startCamera, stopCamera]);

  // 切换导出菜单
  const toggleExportMenu = () => {
    setShowExportMenu(!showExportMenu);

    if (showPlusMenu) {
      setShowPlusMenu(false);
    }

    if (showEmojiPicker) {
      setShowEmojiPicker(false);
    }
  };

  // 导出聊天记录为JSON格式
  const exportChatAsJSON = () => {
    const chatData = {
      chatInfo: {
        currentUser: currentUser.username,
        selectedUser: selectedUser.username,
        exportTime: new Date().toISOString(),
        totalMessages: messages.length,
      },
      messages: messages.map(msg => ({
        id: msg._id,
        from: msg.from,
        to: msg.to,
        message: msg.message,
        messageType: msg.messageType,
        timestamp: msg.timestamp,
        timeString: formatTime(new Date(msg.timestamp)),
      })),
    };

    const dataStr = JSON.stringify(chatData, null, 2);
    const dataBlob = new Blob([dataStr], { type: 'application/json' });
    const url = URL.createObjectURL(dataBlob);
    const link = document.createElement('a');

    link.href = url;
    link.download = `chat_${currentUser.username}_${selectedUser.username}_${new Date().toISOString().split('T')[0]}.json`;
    link.click();
    URL.revokeObjectURL(url);
    setShowExportMenu(false);
  };

  // 导出聊天记录为TXT格式
  const exportChatAsTXT = () => {
    let txtContent = '聊天记录导出\n';
    txtContent += '================================\n';
    txtContent += `导出时间: ${new Date().toLocaleString('zh-CN')}\n`;
    txtContent += `聊天用户: ${currentUser.username} 与 ${selectedUser.username}\n`;
    txtContent += `消息总数: ${messages.length}\n`;
    txtContent += '================================\n\n';

    messages.forEach(msg => {
      const timeStr = formatTime(new Date(msg.timestamp));
      const sender =
        msg.from === currentUser.username ? '我' : selectedUser.username;
      txtContent += `[${timeStr}] ${sender}:\n`;

      if (msg.messageType === 'text') {
        txtContent += `${msg.message}\n\n`;
      } else if (msg.messageType === 'image') {
        txtContent += `[图片] ${msg.message}\n\n`;
      } else if (msg.messageType === 'file') {
        try {
          const fileData = JSON.parse(msg.message);
          txtContent += `[文件] ${fileData.name} (${formatFileSize(fileData.size)})\n`;
        } catch {
          txtContent += `[文件] ${msg.message}\n`;
        }
        txtContent += '\n';
      } else if (msg.messageType === 'voice') {
        try {
          const voiceData = JSON.parse(msg.message);
          txtContent += `[语音] 时长: ${voiceData.duration}秒\n`;
        } catch {
          txtContent += '[语音]\n';
        }
        txtContent += '\n';
      } else if (msg.messageType === 'location') {
        try {
          const locationData = JSON.parse(msg.message);
          txtContent += `[位置] ${locationData.address}\n`;
          txtContent += `坐标: ${locationData.latitude}, ${locationData.longitude}\n`;
        } catch {
          txtContent += '[位置]\n';
        }
        txtContent += '\n';
      } else {
        txtContent += `[${msg.messageType}] ${msg.message}\n\n`;
      }
    });

    const dataBlob = new Blob([txtContent], {
      type: 'text/plain;charset=utf-8',
    });
    const url = URL.createObjectURL(dataBlob);
    const link = document.createElement('a');

    link.href = url;
    link.download = `chat_${currentUser.username}_${selectedUser.username}_${new Date().toISOString().split('T')[0]}.txt`;
    link.click();
    URL.revokeObjectURL(url);
    setShowExportMenu(false);
  };

  // 转义XML特殊字符
  const escapeXml = (text: string) => {
    return text
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;')
      .replace(/"/g, '&quot;')
      .replace(/'/g, '&#39;');
  };

  // 导出聊天记录为SVG格式
  const exportChatAsSVG = () => {
    const svgWidth = 800;
    const svgHeight = Math.max(600, messages.length * 60 + 100);
    let svgContent = `<svg width="${svgWidth}" height="${svgHeight}" xmlns="http://www.w3.org/2000/svg">`;
    svgContent += `<defs>
<style>
.title { font-family: Arial, sans-serif; font-size: 20px; font-weight: bold; fill: #333; }
.subtitle { font-family: Arial, sans-serif; font-size: 14px; fill: #666; }
.message { font-family: Arial, sans-serif; font-size: 12px; fill: #333; }
.time { font-family: Arial, sans-serif; font-size: 10px; fill: #999; }
.sender { font-family: Arial, sans-serif; font-size: 11px; font-weight: bold; fill: #007bff; }
.bubble-sent { fill: #007bff; }
.bubble-received { fill: #e9ecef; }
.text-sent { fill: white; }
.text-received { fill: #333; }
</style>
</defs>`;

    // 标题
    svgContent += `<rect width="${svgWidth}" height="80" fill="#f8f9fa" stroke="#dee2e6" stroke-width="1"/>`;
    svgContent += `<text x="20" y="30" class="title">${escapeXml('聊天记录导出')}</text>`;
    svgContent += `<text x="20" y="50" class="subtitle">${escapeXml(currentUser.username)} 与 ${escapeXml(selectedUser.username)}</text>`;
    svgContent += `<text x="20" y="70" class="subtitle">${escapeXml(`导出时间: ${new Date().toLocaleString('zh-CN')} | 消息总数: ${messages.length}`)}</text>`;

    // 消息
    let yPos = 100;

    messages.forEach(msg => {
      const timeStr = formatTime(new Date(msg.timestamp));
      const sender =
        msg.from === currentUser.username ? '我' : selectedUser.username;
      const isSent = msg.from === currentUser.username;

      // 消息气泡
      const bubbleWidth = 300;
      const bubbleHeight = 40;
      const bubbleX = isSent ? svgWidth - bubbleWidth - 20 : 20;
      const bubbleY = yPos;

      svgContent += `<rect x="${bubbleX}" y="${bubbleY}" width="${bubbleWidth}" height="${bubbleHeight}" 
class="${isSent ? 'bubble-sent' : 'bubble-received'}" rx="10" ry="10"/>`;

      // 发送者
      svgContent += `<text x="${bubbleX + 10}" y="${bubbleY + 15}" class="sender">${escapeXml(sender)}</text>`;

      // 消息内容
      let messageText = msg.message;

      if (msg.messageType === 'image') {
        messageText = '[图片]';
      } else if (msg.messageType === 'file') {
        try {
          const fileData = JSON.parse(msg.message);
          messageText = `[文件] ${fileData.name}`;
        } catch {
          messageText = '[文件]';
        }
      } else if (msg.messageType === 'voice') {
        messageText = '[语音]';
      } else if (msg.messageType === 'location') {
        try {
          const locationData = JSON.parse(msg.message);
          messageText = `[位置] ${locationData.address}`;
        } catch {
          messageText = '[位置]';
        }
      }

      // 截断过长的消息
      if (messageText.length > 30) {
        messageText = messageText.substring(0, 30) + '...';
      }

      svgContent += `<text x="${bubbleX + 10}" y="${bubbleY + 30}" class="${isSent ? 'text-sent' : 'text-received'}">${escapeXml(messageText)}</text>`;

      // 时间
      svgContent += `<text x="${bubbleX + bubbleWidth - 10}" y="${bubbleY + 15}" class="time" text-anchor="end">${escapeXml(timeStr)}</text>`;

      yPos += 60;
    });

    svgContent += '</svg>';

    const dataBlob = new Blob([svgContent], { type: 'image/svg+xml' });
    const url = URL.createObjectURL(dataBlob);
    const link = document.createElement('a');

    link.href = url;
    link.download = `chat_${currentUser.username}_${selectedUser.username}_${new Date().toISOString().split('T')[0]}.svg`;
    link.click();
    URL.revokeObjectURL(url);
    setShowExportMenu(false);
  };

  // 导出聊天记录为HTML格式
  const exportChatAsHTML = () => {
    let htmlContent = `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>聊天记录导出</title>
<style>
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background-color: #f5f5f5; }
.container { max-width: 800px; margin: 0 auto; background: white; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,0.1); }
.header { background: #007bff; color: white; padding: 20px; border-radius: 10px 10px 0 0; }
.header h1 { margin: 0; font-size: 24px; }
.header p { margin: 5px 0 0 0; opacity: 0.9; }
.messages { padding: 20px; }
.message { margin-bottom: 15px; display: flex; }
.message.sent { justify-content: flex-end; }
.message.received { justify-content: flex-start; }
.message-content { max-width: 70%; padding: 10px 15px; border-radius: 18px; position: relative; }
.message.sent .message-content { background: #007bff; color: white; }
.message.received .message-content { background: #e9ecef; color: #333; }
.message-time { font-size: 11px; opacity: 0.7; margin-top: 5px; }
.message-sender { font-weight: bold; margin-bottom: 5px; font-size: 12px; }
.file-info { background: rgba(255,255,255,0.2); padding: 5px; border-radius: 5px; margin-top: 5px; }
.image-message { max-width: 200px; border-radius: 10px; }
.location-info { font-size: 12px; }
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>聊天记录导出</h1>
<p>${currentUser.username} <-> ${selectedUser.username}</p>
<p>导出时间: ${new Date().toLocaleString('zh-CN')} | 消息总数: ${messages.length}</p>
</div>
<div class="messages">`;

    messages.forEach(msg => {
      const timeStr = formatTime(new Date(msg.timestamp));
      const sender =
        msg.from === currentUser.username ? '我' : selectedUser.username;
      const isSent = msg.from === currentUser.username;

      htmlContent += `
<div class="message ${isSent ? 'sent' : 'received'}">
<div class="message-content">
<div class="message-sender">${sender}</div>`;

      if (msg.messageType === 'text') {
        htmlContent += `<div>${msg.message}</div>`;
      } else if (msg.messageType === 'image') {
        htmlContent += `<div>[图片]</div><img src="${msg.message}" alt="聊天图片" class="image-message" onerror="this.style.display='none'">`;
      } else if (msg.messageType === 'file') {
        try {
          const fileData = JSON.parse(msg.message);
          htmlContent += `<div>[文件] ${fileData.name}</div>`;

          if (fileData.size) {
            htmlContent += `<div class="file-info">大小: ${formatFileSize(fileData.size)}</div>`;
          }
        } catch {
          htmlContent += '<div>[文件]</div>';
        }
      } else if (msg.messageType === 'voice') {
        try {
          const voiceData = JSON.parse(msg.message);
          htmlContent += `<div>[语音] 时长: ${voiceData.duration}秒</div>`;
        } catch {
          htmlContent += '<div>[语音]</div>';
        }
      } else if (msg.messageType === 'location') {
        try {
          const locationData = JSON.parse(msg.message);
          htmlContent += `<div class="location-info">[位置] ${locationData.address}</div>`;
          htmlContent += `<div class="location-info">坐标: ${locationData.latitude}, ${locationData.longitude}</div>`;
        } catch {
          htmlContent += '<div>[位置]</div>';
        }
      } else {
        htmlContent += `<div>[${msg.messageType}] ${msg.message}</div>`;
      }

      htmlContent += `
<div class="message-time">${timeStr}</div>
</div>
</div>`;
    });

    htmlContent += `
</div>
</div>
</body>
</html>`;

    const dataBlob = new Blob([htmlContent], {
      type: 'text/html;charset=utf-8',
    });
    const url = URL.createObjectURL(dataBlob);
    const link = document.createElement('a');

    link.href = url;
    link.download = `chat_${currentUser.username}_${selectedUser.username}_${new Date().toISOString().split('T')[0]}.html`;
    link.click();
    URL.revokeObjectURL(url);
    setShowExportMenu(false);
  };

  // 处理跳转到Xq页面
  const handleNavigateToXq = () => {
    localStorage.setItem('selectedUser', JSON.stringify(selectedUser));
    navigate('/xq');
  };

  return (
    <div className="dhat-container">
      {/* 头部 */}
      <div className="dhat-header">
        <button className="back-btn" onClick={onBack}>
          <Icon iconClass="icon-zuojiantou" size={24} />
        </button>
        <div className="user-info">
          <span className="username">{selectedUser.username}</span>
          {isTyping && <span className="typing-indicator">正在输入...</span>}
        </div>
        <div className="header-actions">
          <button
            className="export-btn"
            onClick={toggleExportMenu}
            title="导出聊天记录"
          >
            📤
          </button>
          <button className="three-dots-btn" onClick={handleNavigateToXq}>
            ⋮
          </button>
        </div>
      </div>

      {/* 聊天区域 */}
      <div
        className="chat-messages"
        style={{
          backgroundImage: getChatBackground()
            ? `url(${getChatBackground()})`
            : 'none',
          backgroundSize: 'cover',
          backgroundPosition: 'center',
          backgroundRepeat: 'no-repeat',
          position: 'relative',
        }}
      >
        {/* 背景图遮罩层，确保文字可读性 */}
        {getChatBackground() && (
          <div
            style={{
              position: 'absolute',
              top: 0,
              left: 0,
              right: 0,
              bottom: 0,
              backgroundColor: 'rgba(255, 255, 255, 0.1)',
              pointerEvents: 'none',
            }}
          />
        )}

        {loading ? (
          <div className="loading">加载中...</div>
        ) : (
          <>
            {messages.length > 0 && (
              <>
                {/* 第一条消息的时间 */}
                <div className="time-separator">
                  <span>{formatTime(new Date(messages[0].timestamp))}</span>
                </div>

                {/* 渲染消息和时间分隔符 */}
                {messages.map((msg, index) => (
                  <React.Fragment key={msg._id}>
                    {/* 撤回消息显示 - 像时间分隔符一样居中显示 */}
                    {msg.isRecalled && (
                      <div className="time-separator">
                        <span className="recall-text">
                          {msg.from === currentUser.username
                            ? '你撤回了一条消息'
                            : `${selectedUser.username}撤回了一条消息`}
                        </span>
                        {msg.from === currentUser.username &&
                          msg.originalContent && (
                            <button
                              className="re-edit-btn"
                              onClick={() =>
                                reEditMessage(msg.originalContent!)
                              }
                            >
                              重新编辑
                            </button>
                          )}
                      </div>
                    )}

                    {/* 撤回的消息不显示气泡 */}
                    {!msg.isRecalled && (
                      <div
                        className={`message ${msg.from === currentUser.username ? 'sent' : 'received'}`}
                        style={{
                          position: 'relative',
                          zIndex: 1,
                        }}
                      >
                        <div className="message-content">
                          {msg.messageType === 'image' ? (
                            <div
                              className={`image-message ${msg.from === selectedUser.username ? 'clickable-message' : ''}`}
                              onClick={() =>
                                msg.from === selectedUser.username
                                  ? handleMessageClick(msg)
                                  : window.open(msg.message, '_blank')
                              }
                              style={{
                                cursor:
                                  msg.from === selectedUser.username
                                    ? 'pointer'
                                    : 'default',
                              }}
                            >
                              <img
                                src={msg.message}
                                alt="聊天图片"
                                className="chat-image"
                              />
                              {msg.from === selectedUser.username && (
                                <div className="ai-hint">点击获取AI分析</div>
                              )}
                            </div>
                          ) : msg.messageType === 'video' ? (
                            <div className="video-message">
                              {(() => {
                                try {
                                  let videoData;
                                  if (msg.message.startsWith('{')) {
                                    videoData = JSON.parse(msg.message);
                                  } else {
                                    videoData = {
                                      url: msg.message,
                                      name:
                                        msg.message.split('/').pop() || '视频',
                                      size: 0,
                                      type: 'video/webm',
                                    };
                                  }

                                  return (
                                    <>
                                      <video
                                        controls
                                        className="chat-video"
                                        preload="metadata"
                                      >
                                        <source
                                          src={videoData.url}
                                          type={videoData.type}
                                        />
                                        您的浏览器不支持视频播放
                                      </video>
                                      <div className="video-info">
                                        {videoData.size > 0 && (
                                          <span className="video-size">
                                            {formatFileSize(videoData.size)}
                                          </span>
                                        )}
                                      </div>
                                    </>
                                  );
                                } catch {
                                  return (
                                    <div className="video-message">
                                      <video
                                        controls
                                        className="chat-video"
                                        preload="metadata"
                                      >
                                        <source
                                          src={msg.message}
                                          type="video/webm"
                                        />
                                        您的浏览器不支持视频播放
                                      </video>
                                    </div>
                                  );
                                }
                              })()}
                            </div>
                          ) : msg.messageType === 'file' ? (
                            <div
                              className={`file-message ${msg.from === selectedUser.username ? 'clickable-message' : ''}`}
                              onClick={() =>
                                msg.from === selectedUser.username &&
                                handleMessageClick(msg)
                              }
                              style={{
                                cursor:
                                  msg.from === selectedUser.username
                                    ? 'pointer'
                                    : 'default',
                              }}
                            >
                              {(() => {
                                try {
                                  let fileData;
                                  if (msg.message.startsWith('{')) {
                                    fileData = JSON.parse(msg.message);
                                  } else {
                                    fileData = {
                                      url: msg.message,
                                      name:
                                        msg.message.split('/').pop() || '文件',
                                      size: 0,
                                      type: 'unknown',
                                    };
                                  }

                                  return (
                                    <>
                                      <div className="file-icon">📁</div>
                                      <div className="file-info">
                                        <div className="file-name">
                                          {fileData.name}
                                        </div>
                                        {fileData.size > 0 && (
                                          <div className="file-size">
                                            {formatFileSize(fileData.size)}
                                          </div>
                                        )}
                                      </div>
                                      <button
                                        className="download-btn"
                                        onClick={() => {
                                          if (fileData.url) {
                                            window.open(fileData.url, '_blank');
                                          }
                                        }}
                                      >
                                        下载
                                      </button>
                                    </>
                                  );
                                } catch {
                                  return (
                                    <>
                                      <div className="file-icon">📁</div>
                                      <div className="file-info">
                                        <div className="file-name">文件</div>
                                      </div>
                                      <button
                                        className="download-btn"
                                        onClick={() => {
                                          if (msg.message.startsWith('http')) {
                                            window.open(msg.message, '_blank');
                                          }
                                        }}
                                      >
                                        下载
                                      </button>
                                    </>
                                  );
                                }
                              })()}
                            </div>
                          ) : msg.messageType === 'location' ? (
                            <div
                              className={`location-message ${msg.from === selectedUser.username ? 'clickable-message' : ''}`}
                              onClick={() =>
                                msg.from === selectedUser.username &&
                                handleMessageClick(msg)
                              }
                              style={{
                                cursor:
                                  msg.from === selectedUser.username
                                    ? 'pointer'
                                    : 'default',
                              }}
                            >
                              {(() => {
                                try {
                                  const locationData = JSON.parse(msg.message);

                                  return (
                                    <>
                                      <div className="location-map">
                                        <img
                                          src={`http://localhost:3001/ysx/staticmap?location=${locationData.longitude},${locationData.latitude}`}
                                          alt="位置地图"
                                          className="chat-map"
                                          onClick={() => {
                                            window.open(
                                              `https://uri.amap.com/marker?position=${locationData.longitude},${locationData.latitude}&name=${encodeURIComponent(locationData.address)}`,
                                              '_blank'
                                            );
                                          }}
                                        />
                                      </div>
                                      <div className="location-info">
                                        <div className="location-address">
                                          {locationData.address}
                                        </div>
                                        <div className="location-coords">
                                          {locationData.latitude.toFixed(6)},{' '}
                                          {locationData.longitude.toFixed(6)}
                                        </div>
                                      </div>
                                    </>
                                  );
                                } catch {
                                  return (
                                    <div className="location-error">
                                      位置信息解析失败
                                    </div>
                                  );
                                }
                              })()}
                            </div>
                          ) : msg.messageType === 'voice' ? (
                            <div
                              className={`voice-message ${msg.from === selectedUser.username ? 'clickable-message' : ''}`}
                              onClick={() =>
                                msg.from === selectedUser.username &&
                                handleMessageClick(msg)
                              }
                              style={{
                                cursor:
                                  msg.from === selectedUser.username
                                    ? 'pointer'
                                    : 'default',
                              }}
                            >
                              {(() => {
                                try {
                                  const voiceData = JSON.parse(msg.message);
                                  const isPlaying = playingVoiceId === msg._id;

                                  return (
                                    <div className="voice-message">
                                      <button
                                        className="voice-play-btn"
                                        onClick={() =>
                                          playVoiceMessage(
                                            voiceData.url,
                                            msg._id
                                          )
                                        }
                                      >
                                        <svg
                                          width="16"
                                          height="16"
                                          viewBox="0 0 24 24"
                                          fill="currentColor"
                                        >
                                          <path d="M8 5v14l11-7z" />
                                        </svg>
                                      </button>
                                      <div className="voice-duration">
                                        {voiceData.duration}
                                      </div>
                                      <div
                                        className={`voice-waveform ${isPlaying ? 'playing' : ''}`}
                                      >
                                        <span></span>
                                        <span></span>
                                        <span></span>
                                        <span></span>
                                        <span></span>
                                      </div>
                                    </div>
                                  );
                                } catch {
                                  return (
                                    <div className="voice-error">
                                      语音信息解析失败
                                    </div>
                                  );
                                }
                              })()}
                            </div>
                          ) : (
                            <p
                              className={`message-text ${msg.from === selectedUser.username ? 'clickable-message' : ''}`}
                              onClick={() =>
                                msg.from === selectedUser.username &&
                                handleMessageClick(msg)
                              }
                              style={{
                                cursor:
                                  msg.from === selectedUser.username
                                    ? 'pointer'
                                    : 'default',
                              }}
                            >
                              {msg.message}
                            </p>
                          )}
                        </div>

                        {/* 撤回按钮 - 只在自己的消息上显示，且未撤回，且发送时间在2分钟内，且是真实的消息ID */}
                        {msg.from === currentUser.username &&
                          !msg.isRecalled &&
                          (() => {
                            const isRealMessageId = /^[0-9a-fA-F]{24}$/.test(
                              msg._id
                            );

                            if (!isRealMessageId) {
                              console.warn('跳过临时消息的撤回按钮', msg._id);
                              return null;
                            }

                            const now = new Date();
                            const messageTime = new Date(msg.timestamp);
                            const timeDiff =
                              now.getTime() - messageTime.getTime();
                            const twoMinutes = 2 * 60 * 1000;

                            return timeDiff <= twoMinutes ? (
                              <div className="message-actions">
                                <button
                                  className="recall-btn"
                                  onClick={() => recallMessage(msg._id)}
                                  title="撤回消息"
                                >
                                  撤回
                                </button>
                              </div>
                            ) : null;
                          })()}
                      </div>
                    )}

                    {/* 如果下一条消息时间间隔超过2分钟，显示时间分隔符 */}
                    {index < messages.length - 1 &&
                      (() => {
                        const currentTime = new Date(msg.timestamp);
                        const nextTime = new Date(
                          messages[index + 1].timestamp
                        );
                        const timeDiff =
                          nextTime.getTime() - currentTime.getTime();
                        const minutesDiff = timeDiff / (1000 * 60);

                        if (minutesDiff > 2) {
                          return (
                            <div className="time-separator">
                              <span>{formatTime(nextTime)}</span>
                            </div>
                          );
                        }

                        return null;
                      })()}
                  </React.Fragment>
                ))}
              </>
            )}
          </>
        )}

        <div ref={messagesEndRef} />
      </div>

      {/* 语音输入状态显示 */}
      {isVoiceInputting && (
        <div className="voice-input-status">
          <div className="voice-input-indicator">
            <div className="voice-wave-animation">
              <span></span>
              <span></span>
              <span></span>
              <span></span>
              <span></span>
            </div>
            <span className="voice-input-text">正在录音，点击停止...</span>
          </div>
        </div>
      )}

      {/* 输入区域 */}
      <div className="message-input">
        <div className="input-container">
          {/* 语音录制按钮 */}
          <button
            className={`voice-btn ${isRecording ? 'recording' : ''}`}
            onClick={handleVoiceRecord}
            title={isRecording ? '点击停止录音' : '点击开始录音'}
          >
            <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor">
              <path d="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3 3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6 6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" />
            </svg>
            {isRecording && (
              <span className="recording-time">{recordingTime}s</span>
            )}
          </button>

          <input
            type="text"
            value={newMessage}
            onChange={handleInputChange}
            onKeyPress={handleKeyPress}
            placeholder="输入消息..."
            className="input-field"
          />

          {/* 表情包按钮 */}
          <div className="button-container" style={{ position: 'relative' }}>
            <div className="emoji">
              <BsEmojiSmileFill onClick={toggleEmojiPicker} />
            </div>

            {/* 表情包选择器 */}
            {showEmojiPicker && (
              <div
                style={{
                  position: 'absolute',
                  bottom: '48px',
                  right: -75,
                  zIndex: 2000,
                  background: '#fff',
                  borderRadius: '16px',
                  boxShadow: '0 4px 24px rgba(0,0,0,0.15)',
                  padding: '8px',
                  width: '350px',
                  maxHeight: '350px',
                  overflow: 'auto',
                  transition: 'all 0.2s',
                  marginLeft: '200px',
                }}
              >
                <EmojiPicker
                  onEmojiClick={handleEmojiClick}
                  width={300}
                  searchDisabled={false}
                  skinTonesDisabled={false}
                  previewConfig={{ showPreview: false }}
                />
              </div>
            )}
          </div>

          {/* 加号按钮 */}
          <div className="button-container" style={{ position: 'relative' }}>
            <div>
              <span onClick={togglePlusMenu}>
                <Icon iconClass="icon-jiahao" size={24} />
              </span>
            </div>

            {/* 加号功能菜单 */}
            {showPlusMenu && (
              <div className="plus-menu">
                <div
                  className="menu-item"
                  onClick={() =>
                    document.getElementById('image-upload')?.click()
                  }
                >
                  <span className="menu-icon">
                    <Icon iconClass="icon-xiangji1" size={24} />
                  </span>
                  <span className="menu-text">图片</span>
                </div>

                <div
                  className="menu-item"
                  onClick={() =>
                    document.getElementById('file-upload')?.click()
                  }
                >
                  <span className="menu-icon">
                    <Icon iconClass="icon-kaiwenjianjia" size={24} />
                  </span>
                  <span className="menu-text">文件</span>
                </div>

                <div className="menu-item" onClick={() => setShowCamera(true)}>
                  <span className="menu-icon">
                    <Icon iconClass="icon-shipintonghua-tianchong" size={24} />
                  </span>
                  <span className="menu-text">拍摄</span>
                </div>

                <div
                  className="menu-item"
                  onClick={() => setShowLocationPicker(true)}
                >
                  <span className="menu-icon">
                    <Icon iconClass="icon-position" size={24} />
                  </span>
                  <span className="menu-text">位置</span>
                </div>

                <div className="menu-item" onClick={handleVoiceInput}>
                  <span className="menu-icon">
                    <Icon iconClass="icon-maikefeng" size={24} />
                  </span>
                  <span className="menu-text">
                    {isVoiceInputting ? '停止录音' : '语音转文字'}
                  </span>
                </div>

                <div className="menu-item" onClick={startVoiceCall}>
                  <span className="menu-icon">
                    <Icon iconClass="icon-yuyintonghua" size={24} />
                  </span>
                  <span className="menu-text">语音通话</span>
                </div>

                <div className="menu-item" onClick={startVideoCall}>
                  <span className="menu-icon">
                    <Icon iconClass="icon-shipintonghua-tianchong" size={24} />
                  </span>
                  <span className="menu-text">视频通话</span>
                </div>

                {/* 隐藏的文件输入 */}
                <input
                  id="image-upload"
                  type="file"
                  accept="image/*"
                  onChange={handleImageUpload}
                  style={{ display: 'none' }}
                />
                <input
                  id="file-upload"
                  type="file"
                  onChange={handleFileUpload}
                  style={{ display: 'none' }}
                />
              </div>
            )}
          </div>
        </div>
      </div>

      {/* 相机弹窗 */}
      {showCamera && (
        <div className="camera-overlay">
          <div className="camera-container">
            <div className="camera-header">
              <button
                className="close-btn"
                onClick={() => {
                  setShowCamera(false);
                  stopCamera();
                }}
              >
                ×
              </button>
              <div className="camera-title">
                {cameraMode === 'photo' ? '拍照' : '录制视频'}
              </div>
              <button className="mode-toggle" onClick={toggleCameraMode}>
                {cameraMode === 'photo' ? (
                  <Icon
                    iconClass="icon-shipintonghua-tianchong"
                    size={24}
                    color={'white'}
                  />
                ) : (
                  <Icon
                    iconClass="icon-shipintonghua-tianchong"
                    size={24}
                    color={'white'}
                  />
                )}
              </button>
            </div>

            <div className="camera-preview">
              <video
                ref={videoRef}
                autoPlay
                playsInline
                muted
                className="camera-video"
              />
              <canvas ref={canvasRef} style={{ display: 'none' }} />
            </div>

            <div className="camera-controls">
              {cameraMode === 'photo' ? (
                <button className="capture-btn photo-btn" onClick={takePhoto}>
                  <Icon iconClass="icon-xiangji1" size={24} />
                </button>
              ) : (
                <div className="video-controls">
                  {!isRecording ? (
                    <button
                      className="capture-btn record-btn"
                      onClick={startRecording}
                    >
                      🔴
                    </button>
                  ) : (
                    <button
                      className="capture-btn stop-btn"
                      onClick={stopRecording}
                    >
                      ⏹️
                    </button>
                  )}
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* 位置选择器弹窗 */}
      {showLocationPicker && (
        <div className="location-overlay">
          <div className="location-container">
            <div className="location-header">
              <button
                className="close-btn"
                onClick={() => {
                  setShowLocationPicker(false);
                  resetMapSelection();
                }}
              >
                ×
              </button>
              <div className="location-title">发送位置</div>
            </div>

            <div className="location-content">
              {!currentLocation && !selectedMapLocation ? (
                <div className="location-get">
                  <button
                    className="get-location-btn"
                    onClick={getCurrentLocation}
                    disabled={locationLoading}
                  >
                    {locationLoading ? '获取中...' : '获取位置'}
                  </button>

                  <div className="location-divider">或者</div>

                  <div className="location-map-select">
                    <div className="map-select-text">点击地图选择位置</div>
                    <div
                      className="map-container"
                      onClick={handleMapClick}
                      style={{ position: 'relative', cursor: 'pointer' }}
                    >
                      <img
                        src="http://localhost:3001/ysx/staticmap?location=116.3974,39.9093&zoom=12&size=400*300&key=3c2435fbf083688044800e1cf0356dd2"
                        alt="地图选择器"
                        className="map-selector"
                        style={{
                          width: '100%',
                          height: 'auto',
                          borderRadius: '8px',
                        }}
                      />
                      {mapLoading && (
                        <div className="map-loading">获取地址中...</div>
                      )}
                    </div>
                  </div>
                </div>
              ) : (
                <div className="location-preview">
                  <div className="location-map">
                    <img
                      src={`http://localhost:3001/ysx/staticmap?location=${(selectedMapLocation || currentLocation)?.longitude},${(selectedMapLocation || currentLocation)?.latitude}`}
                      alt="位置地图"
                      className="preview-map"
                    />
                  </div>

                  <div className="location-details">
                    <div className="location-address">
                      {(selectedMapLocation || currentLocation)?.address}
                    </div>
                    <div className="location-coords">
                      {(
                        selectedMapLocation || currentLocation
                      )?.latitude.toFixed(6)}
                      ,{' '}
                      {(
                        selectedMapLocation || currentLocation
                      )?.longitude.toFixed(6)}
                    </div>
                  </div>

                  <div className="location-actions">
                    <button
                      className="reset-location-btn"
                      onClick={resetMapSelection}
                    >
                      重新选择
                    </button>
                    <button
                      className="send-location-btn"
                      onClick={sendLocation}
                    >
                      发送位置
                    </button>
                  </div>
                </div>
              )}
            </div>
          </div>
        </div>
      )}

      {/* 导出菜单弹窗 */}
      {showExportMenu && (
        <div className="export-overlay">
          <div className="export-container">
            <div className="export-header">
              <button
                className="close-btn"
                onClick={() => setShowExportMenu(false)}
              >
                ×
              </button>
              <div className="export-title">导出聊天记录</div>
            </div>

            <div className="export-content">
              <div className="export-info">
                <p>选择导出格式：</p>
                <p className="export-detail">
                  {currentUser.username} 与 {selectedUser.username}
                </p>
                <p className="export-detail">消息总数: {messages.length}</p>
              </div>

              <div className="export-options">
                <button className="export-option" onClick={exportChatAsJSON}>
                  <div className="export-icon">📄</div>
                  <div className="export-text">
                    <div className="export-format">JSON</div>
                    <div className="export-desc">结构化数据格式</div>
                  </div>
                </button>

                <button className="export-option" onClick={exportChatAsTXT}>
                  <div className="export-icon">📝</div>
                  <div className="export-text">
                    <div className="export-format">TXT</div>
                    <div className="export-desc">纯文本格式</div>
                  </div>
                </button>

                <button className="export-option" onClick={exportChatAsSVG}>
                  <div className="export-icon">🎨</div>
                  <div className="export-text">
                    <div className="export-format">SVG</div>
                    <div className="export-desc">矢量图形格式</div>
                  </div>
                </button>

                <button className="export-option" onClick={exportChatAsHTML}>
                  <div className="export-icon">🌐</div>
                  <div className="export-text">
                    <div className="export-format">HTML</div>
                    <div className="export-desc">网页格式</div>
                  </div>
                </button>
              </div>
            </div>
          </div>
        </div>
      )}

      {/* 语音通话组件 */}
      <VoiceCall
        isVisible={showVoiceCall}
        onClose={closeVoiceCall}
        otherUser={{
          username: selectedUser.username,
          image: selectedUser.image,
        }}
        currentUser={{
          username: currentUser.username,
          image: currentUser.image,
        }}
        socket={socket}
        isIncoming={!!incomingCallData && incomingCallData.type === 'voice'}
        incomingOffer={
          incomingCallData?.type === 'voice'
            ? incomingCallData.offer
            : undefined
        }
        onCallStateChange={handleCallStateChange}
        callState={callState}
        onCallEnded={handleCallEnded}
        isCallInitiator={!incomingCallData}
      />

      {/* 视频通话组件 */}
      <VideoCall
        isVisible={showVideoCall}
        onClose={closeVideoCall}
        otherUser={{
          username: selectedUser.username,
          image: selectedUser.image,
        }}
        currentUser={{
          username: currentUser.username,
          image: currentUser.image,
        }}
        socket={socket}
        isIncoming={!!incomingCallData && incomingCallData.type === 'video'}
        incomingOffer={
          incomingCallData?.type === 'video'
            ? incomingCallData.offer
            : undefined
        }
        onCallStateChange={handleCallStateChange}
        callState={callState}
        onCallEnded={handleCallEnded}
        isCallInitiator={!incomingCallData}
      />

      {/* AI弹窗组件 */}
      <AIModal
        isVisible={showAIModal}
        onClose={closeAIModal}
        message={selectedMessage?.message || ''}
        messageType={selectedMessage?.messageType || 'text'}
      />
    </div>
  );
};

export default Dhat;
